# -*- coding:utf-8 -*-
'''
# Author: xiguan
# Mail: xiguan.teng@qq.com
# -----
# Last Modified: 2022-05-13 10:08:31
# Modified By: xiguan
# -----
# Copyright (c) 2022 XiGuan Inc.
# 
# No Bug No error No warning.
# -----
'''

import ftplib
import json
import os
import time
from pickle import loads

from flask import Blueprint, request, session

from config import db_session
from entity.Ignore import Ignore
from entity.Log import Log
from entity.Sync import Sync
from entity.ServerFile import ServerFile



ftpserver = Blueprint('ftp',__name__)

# 创建 FTP 实例
ftp = ftplib.FTP(encoding='gbk')

# 将文件对象转化为 json 格式
def serverfile_2_json(obj):
   return {
      "name": obj.name,
      "size": obj.size,
      "mtime": obj.mtime,
      "chmod": obj.chmod
   }

# 将日志对象转化为 json 格式
def log_2_json(obj):
   return {
        "id": obj.id,
        "uid": obj.uid,
        "username": obj.username,
        "syncdir_id": obj.syncdir_id,
        "syncdir_path": obj.syncdir_path,
        "direction": obj.direction,
        "sync_time": obj.sync_time,
        "server_port": obj.server_port
   }

# 获取服务器端文件信息
@ftpserver.route('/get_server_detail/')
def get_server_detail():
    try:
        # 获取监听端口
        port = request.args.get('port')
        # 连接
        ftp.connect("127.0.0.1", int(port))
        # 登录
        ftp.login('xiguan', 'xiguan')
        # 获取文件目录列表
        filelist = []
        ftp.retrlines('LIST', filelist.append)
        # 存储返回前端的对象
        serverfile_list = []
        for file in filelist:
            name = file.rsplit(" ", 1)[1]  # 文件名
            file = file.rsplit(" ", 1)[0]  # 文件名前面部分
            mtime = file[-12:]  # 文件修改时间
            file = file[:-12]  # 文件修改时间前面部分
            file = file.rstrip()  # 去除右边的空格
            size = file.rsplit(" ", 1)[1]  # 文件大小
            chmod = file.rsplit(" ", 1)[0]  # 文件权限
            serverfile = ServerFile(name=name, size=size, mtime=mtime, chmod=chmod)
            serverfile_list.append(serverfile)
    except Exception:
        return {"status":"NO"}
    return {"status": "OK", "files": json.dumps(serverfile_list, default=serverfile_2_json) }

# 删除服务器端文件或目录
@ftpserver.route('/del_server_file/')
def del_server_file():
    # 获取删除文件名
    name = request.args.get('name')
    # 删除文件或目录
    try:
        # 删除文件
        ftp.delete(name)
    except Exception:
        # 删除目录
        ftp.rmd(name)
    # 返回
    return "OK"

# 新增目录
@ftpserver.route('/add_server_dir/')
def add_server_dir():
    dir_name = request.args.get("name")
    print(dir_name)
    try:
        ftp.mkd(dir_name)
    except Exception:
        return "NO"
    return "OK"

# 重命名文件
@ftpserver.route('/rename_server_file/')
def rename_server_file():
    # 原文件名
    fromname = request.args.get("fromname")
    # 修改文件名
    toname = request.args.get("toname")
    # 修改
    try:
        ftp.rename(fromname, toname)
    except Exception:
        return "NO"
    return "OK"

# 同步文件到本地
@ftpserver.route('/sync_2_local/')
def sync_2_local():
    # 获取当前同步目录编号
    current_syncdir_id = request.args.get("current_syncdir_id")
    # 当前服务端口
    current_server_port = request.args.get("current_server_port")
    # 获取本地路径
    user = loads(session.get("user"))
    # 获取同步目录对象
    syncdirs = list(db_session.query(Sync).filter_by(uid=user.id, id=current_syncdir_id))
    # 获取本地存储路径
    path = syncdirs[0].path
    # 连接
    ftp.connect("127.0.0.1", int(current_server_port))
    # 登录
    ftp.login('xiguan', 'xiguan')

    # 获取文件目录列表
    filelist = []
    # 追加
    ftp.retrlines('LIST', filelist.append)
    # 获取本地存储路径
    local_path = path + ftp.pwd().replace("/", "\\")
    # 遍历文件和目录
    for file in filelist:
        name = file.rsplit(" ", 1)[1]  # 文件名
        # 拼接贝蒂文件路径
        local_path = path + ftp.pwd().replace("/", "\\") + name
        file = file.rsplit(" ", 1)[0]  # 文件名前面部分
        file = file[:-12]  # 文件修改时间前面部分
        file = file.rstrip()  # 去除右边的空格
        chmod = file.rsplit(" ", 1)[0]  # 文件权限
        if chmod[0] == "d":
            is_dir = True
        else:
            is_dir = False
        # 不是目录，直接下载
        if not is_dir:
            try:
                # 以 ASCII 码模式下载文件
                with open(local_path, 'wb') as fp:
                    ftp.retrbinary('RETR ' + name, fp.write)
            except Exception:
                return "NO"
        # 是目录
        else:
            try:
                if not os.path.exists(local_path):
                    # os.rmdir(local_path)
                    os.mkdir(local_path)
            except Exception:
                return "NO"
    # 添加日志，创建时间
    sync_time_array = time.localtime(int(time.time()))
    # 格式化
    sync_style_time = time.strftime("%y/%m/%d %H:%M", sync_time_array)
    # 创建日志对象
    add_log = Log(uid=user.id, username=user.username, syncdir_id=current_syncdir_id, syncdir_path=path, direction="server to client", sync_time=sync_style_time, server_port=current_server_port)
    # 向数据库中添加日志信息
    db_session.add(add_log)
    # 提交
    db_session.commit()
    return "OK"

# 本地文件上传到服务器
@ftpserver.route('/local_upload/')
def local_upload_file():
    # 获取当前同步目录编号
    current_syncdir_id = request.args.get("current_syncdir_id")
    # 获取当前侦听端口
    current_server_port = request.args.get("current_server_port")
    # 获取当前用户名
    current_username = loads(session.get("user")).username
    # 获取当前用户 id
    current_user_id = loads(session.get("user")).id
    # 根据用户 id 和同步目录 id 获取本地同步目录路径
    local_sync_path = list(db_session.query(Sync.path).filter_by(uid=current_user_id, id=current_syncdir_id))[0][0]
    # 根据用户 id 获取忽略列表
    ignore_tuple_list = list(db_session.query(Ignore.name).filter_by(uid=current_user_id, ignore=1))
    # 初始化忽略列表
    ignore_list = []
    # 将元组形式的列表转化为字符串形式的列表
    for tuple in ignore_tuple_list:
        # 添加到列表中
        ignore_list.append(tuple[0])
    # 连接
    ftp.connect("127.0.0.1", int(current_server_port))
    # 登录
    ftp.login('xiguan', 'xiguan')
    # 获取本地同步目录下的所有文件和文件夹
    sync_file_list = os.listdir(local_sync_path)
    # 遍历本地同步目录
    for sync_item_name in sync_file_list:
        # 拼接当前文件或目录的绝对路径
        current_sync_item_path = local_sync_path + "\\" + sync_item_name
        # 判断是否为目录
        if os.path.isdir(current_sync_item_path):
            # 当前为文件夹
            item_type = "D"
        # 不是目录
        else:
            # 当前为文件
            item_type = "F"
        # 如果是文件，直接上传到对应的服务器上
        if item_type == "F":
            # 获取文件名后缀
            current_sync_file_ext = os.path.splitext(sync_item_name)[-1]
            # 该后缀名是否在忽略列表中
            if current_sync_file_ext in ignore_list:
                # 是否时忽略文件
                is_ignore_file = "Y"
            # 不是忽略文件
            else:
                # 赋值
                is_ignore_file = "N"
            # 如果不是忽略文件，以 ASCII 模式上传文件
            if is_ignore_file == "N":
                # 上传
                ftp.storlines('STOR ' + sync_item_name, open(current_sync_item_path,'rb'))
    # 添加日志，创建时间
    sync_time_array = time.localtime(int(time.time()))
    # 格式化
    sync_style_time = time.strftime("%y/%m/%d %H:%M", sync_time_array)
    # 创建日志对象
    add_log = Log(uid=current_user_id, username=current_username, syncdir_id=current_syncdir_id, syncdir_path=local_sync_path, direction="client to server", sync_time=sync_style_time, server_port=current_server_port)
    # 向数据库中添加日志信息
    db_session.add(add_log)
    # 提交
    db_session.commit()
    return "OK"